package com.im.chen.unionpay;

import android.util.Log;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * Created by imchen on 17/03/2018.
 */

public class LogUtil {

    private static String logFilePath = null;
    private static boolean writeFile = false;
    private static int currentLevel;
    static BufferedOutputStream opsInstance = null;
    private final static Long FILE_MAX_SIZE = 10L * 1024L * 1024L;
    private static SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_hhmmss");
    private static SimpleDateFormat logTimeSdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
    private static String timePrefix = "2018-01-01 12:00:00";

    public static void initLogUtil(Level level) {
//        defaultPath=context.getApplicationContext().getFilesDir().getAbsolutePath()+"/iLog";
//        d("LogUtil",defaultPath);
        initLogUtil(level.value, logFilePath);
    }

    public static void initLogUtil(int level) {
        initLogUtil(level, logFilePath);
    }

    public static void initLogUtil(int level, String savePath) {
        if (savePath != null && !"".equals(savePath)) {
            writeFile = true;
            //init file
            initFile(savePath);
            writeContent(getLogDatePrefix() + "++++++++++++++++ start log at this time ++++++++++++++++++");
        }
        currentLevel = level;
    }

    /**
     * init file if file size over than 10MB ,rename to parentDir+"/"+file.getName()+sdf.format(new Date())+".bak"
     *
     * @param filePath
     */
    private static void initFile(String filePath) {
        File file = new File(filePath);
        File parentDir = new File(file.getParent());
        if (!parentDir.exists()) {
            parentDir.mkdirs();
        }
        if (file.exists() && file.isFile()) {
            Long fileSize = file.length();
            if (fileSize > FILE_MAX_SIZE) {
                String newFileName = parentDir + "/" + file.getName() + sdf.format(new Date()) + ".bak";
                File destFile = new File(newFileName);
                file.renameTo(destFile);
            }
        }
        logFilePath = filePath;
    }


    public static void v(String tag, String log) {
        if (currentLevel > Level.VERBOSE.value) {
            return;
        }
        Log.v(tag, log);

        if (writeFile) {
            writeContent(getLogDatePrefix() +" <V/"+tag+">: "+ log);
        }
    }

    public static void d(String tag, String log) {
        if (currentLevel > Level.DEBUG.value) {
            return;
        }
        String detailLog = getCallClassDetail();
        Log.d(tag, detailLog + log);

        if (writeFile) {
            writeContent(getLogDatePrefix() +" (D/"+tag+"): "+ log);
        }
    }

    public static void i(String tag, String log) {
        if (currentLevel > Level.INFO.value) {
            return;
        }
        Log.i(tag, log);

        if (writeFile) {
            writeContent(getLogDatePrefix() +" [I/"+tag+"]: "+ log);
        }
    }

    public static void w(String tag, String log) {
        if (currentLevel > Level.WARM.value) {
            return;
        }
        String detailLog = getCallClassDetail();
        Log.w(tag, detailLog + log);

        if (writeFile) {
            writeContent(getLogDatePrefix() +" |W/"+tag+"|: "+ log);
        }
    }

    public static void e(String tag, String log) {
        if (currentLevel > Level.ERROR.value) {
            return;
        }
        String detailLog = getCallClassDetail();
        Log.e(tag, detailLog + log);

        if (writeFile) {
            writeContent(getLogDatePrefix() +" {E/"+tag+"}: "+ log);
        }
    }


    //    public static void v(String tag,Exception exception){
//        v(tag,exception.toString());
//    }
    public static void d(String tag, Exception exception) {
        d(tag, getExceptionTrace(exception));
    }

    //    public static void i(String tag,Exception exception){
//        i(tag,exception.toString());
//    }
//    public static void w(String tag,Exception exception){
//        w(tag,exception.toString());
//    }
    public static void e(String tag, Exception exception) {
        e(tag, getExceptionTrace(exception));
    }
//    public static void a(String tag,Exception exception){}

//    public static void v(Object object,String log){}
//    public static void d(Object object,String log){}
//    public static void i(Object object,String log){}
//    public static void w(Object object,String log){}
//    public static void e(Object object,String log){}
//    public static void a(Object object,String log){}

//    public static void v(Object object,Exception exception){}
//    public static void d(Object object,Exception exception){}
//    public static void i(Object object,Exception exception){}
//    public static void w(Object object,Exception exception){}
//    public static void e(Object object,Exception exception){}
//    public static void a(Object object,Exception exception){}

    /**
     * get call method class Detail
     *
     * @return the string of "{"+className+"("+methodName+")["+lineNumber+"]}:
     */
    private static String getCallClassDetail() {
        String result = "";
        int index = 2;
        StackTraceElement element[] = (new Throwable()).getStackTrace();
        String className = element[index].getClassName();
        String methodName = element[index].getMethodName();
        String lineNumber = element[index].getLineNumber() + "";
        result = "{" + className + "(" + methodName + ":" + lineNumber + ")}: ";
        return result;
    }

    /**
     * get exception detail
     *
     * @param exception
     * @return
     */
    private static String getExceptionTrace(Exception exception) {
        String result = "";
        exception.printStackTrace();
        StackTraceElement element[] = exception.getStackTrace();
        if (element != null) {
            result += "[" + exception.toString() + "]\n";
            result += "*****************Exception**********************\n";
            for (int i = 0; i < element.length; i++) {
                result += "at " + element[i].getClassName() + "(" + element[i].getMethodName() + ":" + element[i].getLineNumber() + ")\n";
            }
            result += "*****************Exception**********************\n";
            return result;
        }
        return "no more exception detail!";
    }

    private static void writeContent(String content) {
//TODO fix 目录下有目录和文件同名
        try {
            if (opsInstance == null) {
                opsInstance = new BufferedOutputStream(new FileOutputStream(logFilePath, true));
            }
            opsInstance.write((content + "\n").getBytes("UTF-8"));
            opsInstance.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {

        }
    }

    private static void fileRename(File file, String newFileName) {
        BufferedInputStream bufips = null;
        BufferedOutputStream bufops = null;
        int buffer;
        try {
            bufips = new BufferedInputStream(new FileInputStream(file));
            File newFile = new File(newFileName);
            bufops = new BufferedOutputStream(new FileOutputStream(newFile));
            while ((buffer = bufips.read()) != -1) {
                bufops.write(buffer);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {

            try {
                if (bufops != null) {
                    bufops.close();
                }
                if (bufips != null) {
                    bufips.close();
                }
                //delete original file
                file.delete();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }

    private static String getLogDatePrefix() {
        timePrefix = logTimeSdf.format(new Date());
        return timePrefix ;
    }


}

enum Level {
    VERBOSE(Log.VERBOSE),
    DEBUG(Log.DEBUG),
    INFO(Log.INFO),
    WARM(Log.WARN),
    ERROR(Log.ERROR),
    ASSERT(Log.ASSERT),
    CLOSE(Log.ASSERT + 1);
    int value;

    Level(int value) {
        this.value = value;
    }
}